
import { isUndef, isObject, isDef, hasOwn, hyphenate} from '../../util/index'
import { VNode } from '../vdom/vnode'
import { callHook , updateChildComponent, activeInstance} from '../instance/lifecycle'

const componentVNodeHooks = {
    init(vnode) {
        if (
            vnode.componentInstance &&
            !vnode.componentInstance._isDestroyed &&
            vnode.data.keepAlive
        ) {
            //被keep-alive的组件
            const mountedNode = vnode
            componentVNodeHooks.prepatch(mountedNode, mountedNode)
        } else {
            const child = vnode.componentInstance = createComponentInstanceForVnode(
                vnode,
                activeInstance
            )
            child.$mount(undefined)
        }
    }, 

    prepatch(oldVnode, vnode) {
        // if(!oldVnode.componentInstance){
        //     return
        // }
        const options = vnode.componentOptions
        const child = vnode.componentInstance = oldVnode.componentInstance
       
        updateChildComponent(
            child,
            options.propsData, // updated props
            vnode, // new parent vnode
            options.children // new children
        )
    },

    insert(vnode) {
        const { componentInstance } = vnode
        if (!componentInstance._isMounted) {
            componentInstance._isMounted = true
            callHook(componentInstance, 'mounted')
        }
        if (vnode.data.keepAlive) {
            callHook(componentInstance, 'activated')
        }
    },

    destroy(vnode) {
        // const { componentInstance } = vnode
        // if (!componentInstance._isDestroyed) {
        //     if (!vnode.data.keepAlive) {
        //         componentInstance.$destroy()
        //     } else {
        //         deactivateChildComponent(componentInstance, true /* direct */)
        //     }
        // }
    }
}

const hooksToMerge = Object.keys(componentVNodeHooks)

export function createComponent(
    Ctor,
    data,
    context,
    children,
    tag
) {

    if (isUndef(Ctor)) {
        return
    }
    const baseCtor = context.$options._base
    if (isObject(Ctor)) {
        Ctor = baseCtor.extend(Ctor)
    }
    data = data || {}
    const listeners = data.on
    const propsData = extractPropsFromVNodeData(data, Ctor, tag)

    installComponentHooks(data)
    const name = Ctor.options.name || tag

    const vnode = new VNode(
        `vue-component-${Ctor.cid}-${name}`,
        data, undefined, undefined, undefined, context,
        { Ctor, propsData, listeners, tag, children },
    )

    return vnode
}
export function createComponentInstanceForVnode(
    vnode,
    parent,
) {
    const options = {
        _isComponent: true,
        _parentVnode: vnode,
        parent
    }
    return new vnode.componentOptions.Ctor(options)
}
function installComponentHooks(data) {
    const hooks = data.hook || (data.hook = {})
    for (let i = 0; i < hooksToMerge.length; i++) {
        const key = hooksToMerge[i]
        hooks[key] = componentVNodeHooks[key]
    }
}

function extractPropsFromVNodeData(data, Ctor) {
    const propOptions = Ctor.options.props
    if (isUndef(propOptions)) {
        return
    }
    const res = {}
    const { attrs } = data
    if (isDef(attrs)) {
        for (const key in propOptions) {
            const keyCompile = hyphenate(key)
            if(hasOwn(attrs, keyCompile)){
                res[key] = attrs[keyCompile];
                delete attrs[keyCompile]
            }
        }
    }
    return res
}

 